﻿namespace TomatoBreak.ExtensionMethods
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;

    public static class ObjectExtensions
    {
        [DebuggerStepThrough]
        public static T To<T>(this object instance)
        {
            return (T)instance;
        }

        [DebuggerStepThrough]
        public static T As<T>(this object instance)
        {
            return instance == null ? default(T) : (T)instance;
        }

        [DebuggerStepThrough]
        public static IDictionary<string, object> ToDictionary(
            this object instance)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            return instance.GetType()
                           .GetProperties()
                           .Where(property =>
                               property.CanRead &&
                               !property.GetIndexParameters().Any())
                           .ToDictionary(
                                property => property.Name,
                                property => property.GetValue(instance, null),
                                StringComparer.OrdinalIgnoreCase);
        }

        [DebuggerStepThrough]
        public static void Merge<TTo, TFrom>(this TTo instance, TFrom source)
            where TTo : class where TFrom : class
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            var properties = instance.GetType()
                                     .GetProperties()
                                     .Where(property =>
                                         property.CanWrite &&
                                         !property.GetIndexParameters().Any())
                                     .ToDictionary(
                                        p => p.Name,
                                        p => p,
                                        StringComparer.OrdinalIgnoreCase);

            foreach (var pair1 in source.ToDictionary()
                                        .Where(pair2 =>
                                            properties.ContainsKey(pair2.Key)))
            {
                properties[pair1.Key].SetValue(instance, pair1.Value, null);
            }
        }
    }
}